#pragma once

class CPeHeader
{
private:
    std::string m_DosHeader;
    std::string m_NtHeaders;

    CPeHeader() { }

public:
    CPeHeader(std::string dos, std::string nt) : m_DosHeader(dos), m_NtHeaders(nt) { }
    ~CPeHeader() {}

public:
    std::string GetDosHeader() const { return m_DosHeader; }
    std::string GetNtHeaders() const { return m_NtHeaders; }
};

class CPeSection
{
private:
    std::string m_Section;

    CPeSection() {}

public:
    CPeSection(std::string section) : m_Section(section) {}
    ~CPeSection() {}

public:
    std::string GetSection() const { return m_Section; }
};

struct IBuilder
{
    virtual void BuildPeHeader(CPeHeader& PeHeader) = 0;
    virtual void BuildPeBody(std::vector<CPeSection*>& vtPeSection) = 0;
    virtual std::string GetPeFile() const = 0;
};

class CBuilder : public IBuilder
{
    std::string m_PeFile;

public:
    CBuilder() { m_PeFile = ""; }
    virtual ~CBuilder() {}

public:
    std::string GetPeFile() const { return m_PeFile; }

public:
    virtual void BuildPeHeader(CPeHeader& PeHeader) override
    {
        m_PeFile += PeHeader.GetDosHeader();
        m_PeFile += "\r\n";
        m_PeFile += PeHeader.GetNtHeaders();
        m_PeFile += "\r\n";
    }

    virtual void BuildPeBody(std::vector<CPeSection*>& vtPeSection) override
    {
        for (auto it = vtPeSection.begin(); it != vtPeSection.end(); ++it)
        {
            m_PeFile += (*it)->GetSection();
            m_PeFile += "\r\n";
        }
    }
};

class CGuiBuilder : public IBuilder
{
    std::string m_PeFile;

public:
    CGuiBuilder() { m_PeFile = ""; }
    virtual ~CGuiBuilder() {}

public:
    std::string GetPeFile() const { return m_PeFile; }

public:
    virtual void BuildPeHeader(CPeHeader& PeHeader) override
    {
        m_PeFile += PeHeader.GetDosHeader();
        m_PeFile += "\r\n";
        m_PeFile += PeHeader.GetNtHeaders();
        m_PeFile += "\r\n";
    }

    virtual void BuildPeBody(std::vector<CPeSection*>& vtPeSection) override
    {
        for (auto it = vtPeSection.begin(); it != vtPeSection.end(); ++it)
        {
            m_PeFile += (*it)->GetSection();
            m_PeFile += "\r\n";
        }

        m_PeFile += "rsrc";
        m_PeFile += "\r\n";
    }
};

class CConstructor
{
    IBuilder* m_lpIBuilder;

public:
    CConstructor(IBuilder* lpIBuilder) : m_lpIBuilder(lpIBuilder) {}
    ~CConstructor() {}

public:
    void Construct(CPeHeader& PeHeader, std::vector<CPeSection*>& vtPeSection)
    {
        m_lpIBuilder->BuildPeHeader(PeHeader);
        m_lpIBuilder->BuildPeBody(vtPeSection);
        std::cout << m_lpIBuilder->GetPeFile() << std::endl;
    }
};